import datetime
import re
import time
import traceback
import requests
import logging
import os
from distutils.util import strtobool
from urllib.parse import quote
from collections import OrderedDict, defaultdict
from django.db.models import Count, F, Prefetch
from django.http import Http404, FileResponse
from django.utils import timezone
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.decorators import api_view
from rest_framework import viewsets, views, generics, mixins
from rest_framework.response import Response
from rest_framework.filters import SearchFilter
from asset.serializers import trend_graph_serializer
from strategy.models import Strategy, CreditGlobalAction
from userdata.models import UserScore, UserCreditScoreDetails, UserCreditScore
from mongolog.models import AppsLog, StrategyLog, ShareLog, CASLog, UserActivityLog
from mongolog.serializers import UserActivityLogSerializer, UserWarningSerializer
from mongolog.utils import date_eq, date_range
from tools.datetime import date_filter, as_datetime, to_date, now, range_date
from tools.pagination import PageSizePagination
from tools.doc.doc_script import handler_user_info, exportWord
from tools.mqtt.push import push_message
from zmad.models import ZTPGroup, ZTPUser, ZTPUserCas
from ztp_backend.permissions import IsUUIDPermission
from .serializers import (
    GroupSerializer, UserDetailSerializer, UserDeviceSerializer,
    DailySummarySerializer,
    relationship_serializer, app_visit_serializer, device_geotrack_serializer
)
from .filters import UserFilter
from tools.ipip import find_ip_location
from .models import UserDemand, DailySummary, UserSafetyScore, UserScore, User, Device
from asset.models import Device as ZTPDevice
from ztp_backend.settings import TOTAL_SAFETY_SCORE, DEFAULT_PLATFORM, \
    MEDIUM_SCORE, USER_PROFILE, BEHAVIOUR_PREFERENCE, USER_RELATION, TERMINAL_SECURITY, WITH_WX, BASE_DIR
from tools.utils import get_risk_level, get_uid_info
from django.conf import settings
from rest_framework import status
# Create your views here.

logger = logging.getLogger(__name__)


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """用户列表 & 用户详情"""
    if WITH_WX:
        queryset = ZTPUser.objects.exclude(wx_user_id="")
    else:
        queryset = ZTPUser.objects
    queryset = queryset.order_by('username') \
        .select_related('belong_to') \
        .prefetch_related(
        Prefetch(
            'demands',
            queryset=UserDemand.objects.filter(demand__isnull=False),
            to_attr='nonnull_demands'
        ),
    )
    # permission_classes = (IsUUIDPermission,)
    serializer_class = UserDetailSerializer
    pagination_class = PageSizePagination
    filter_backends = (SearchFilter, DjangoFilterBackend)
    # filterset_class = UserFilter  # 按需求、是否活跃、是否异常筛选（目前注释掉，该方案无法展示今日数据）
    search_fields = ('username', 'name')
    ordering_fields = ('partner_count', 'app_count', 'visit_count', 'safety_score')  # 这里的排序是自行实现的，没有调用OrderingFilter
    lookup_field = 'username'

    def get_queryset(self):
        queryset = super().get_queryset()
        start_date = self.request.query_params.get('start_date')
        end_date = self.request.query_params.get("end_date")
        # 按照组织筛选
        belong_to = self.request.query_params.get('belong_to')
        recursively = self.request.query_params.get('recursively', 'false')
        # 按照策略筛选
        strategy_uid = self.request.query_params.get('strategy_uid')
        # 按照策略类别筛选
        strategy_category = self.request.query_params.get('strategy_category')
        # 按用户活跃度筛选
        is_active = self.request.query_params.get('is_active')
        # 按用户是否异常筛选
        is_abnormal = self.request.query_params.get('is_abnormal')
        active_query = {
            'auth_result': {'$regex': r'_SUCCESS$'},
            # 'auth_code': 7,
            'auth_code': {'$in': [1, 7]},
            'username': {
                '$exists': True,
                '$ne': ''
            },
            # 'log_time': {"$gte": date_from, "$lte": date_to},
        }
        if DEFAULT_PLATFORM:
            active_query.update({'platform': DEFAULT_PLATFORM})
        abnormal_query = {
            'username': {
                '$exists': True,
                '$ne': ''
            },
            "uid": {"$ne": "STG/AUTH-3"}
        }
        if DEFAULT_PLATFORM:
            abnormal_query.update({'platform': DEFAULT_PLATFORM})

        # 活跃，异常用户的判断是有时间窗口的
        if start_date and end_date:
            # 将传入东八区时间转换为带时区的时间对象,转入MongoDB进行查询
            start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d")
            end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d")
            date_from = timezone.make_aware(datetime.datetime.combine(start_date, datetime.time.min))
            # 设置结束时间为该日期的23:59:59.999999，并考虑时区
            date_to = timezone.make_aware(datetime.datetime.combine(end_date, datetime.time.max)) + datetime.timedelta(
                microseconds=999999)
            date_from = as_datetime(date_from)
            date_to = as_datetime(date_to)
            if date_from and date_to:
                active_query.update({'log_time': {"$gte": date_from, "$lte": date_to}})
                abnormal_query.update({'log_time': {"$gte": date_from, "$lte": date_to}})

            if is_active:
                usernames = CASLog.objects.mongo_distinct(
                    'username', active_query
                )
                queryset = queryset.filter(username__in=usernames)
            elif is_abnormal:
                usernames = set(StrategyLog.objects.mongo_distinct(
                    'username', abnormal_query
                ))
                queryset = queryset.filter(username__in=usernames)
            elif strategy_uid:
                usernames = StrategyLog.objects.mongo_distinct(
                    'username',
                    {
                        'username': {
                            '$exists': True,
                            '$ne': ''
                        },
                        'log_time': {"$gte": date_from, "$lte": date_to},
                        'uid': strategy_uid
                    }
                )
                queryset = queryset.filter(username__in=usernames)
            elif strategy_category:
                usernames = StrategyLog.objects.mongo_distinct(
                    'username',
                    {
                        'username': {
                            '$exists': True,
                            '$ne': ''
                        },
                        'log_time': {"$gte": date_from, "$lte": date_to},
                        'meta.category': strategy_category
                    }
                )
                queryset = queryset.filter(username__in=usernames)


            else:
                usernames = UserActivityLog.objects.mongo_distinct(
                    'username',
                    {
                        'username': {
                            '$exists': True,
                            '$ne': ''
                        },
                        'log_time': {"$gte": date_from, "$lte": date_to},
                    }
                )
                queryset = queryset.filter(username__in=usernames)

        else:
            if is_active:
                active_users = set(CASLog.objects.mongo_distinct(
                    'username', active_query,
                ))
                # print("active_users : ", active_users)
                queryset = queryset.filter(username__in=active_users)

            if is_abnormal:
                abnormal_users = set(StrategyLog.objects.mongo_distinct(
                    'username', abnormal_query
                ))
                # print("abnormal_users : ", abnormal_users)
                queryset = queryset.filter(username__in=abnormal_users)

            if strategy_uid:
                usernames = StrategyLog.objects.mongo_distinct(
                    'username',
                    {
                        'username': {
                            '$exists': True,
                            '$ne': ''
                        },
                        'uid': strategy_uid
                    }
                )
                queryset = queryset.filter(username__in=usernames)

            if strategy_category:
                usernames = StrategyLog.objects.mongo_distinct(
                    'username',
                    {
                        'username': {
                            '$exists': True,
                            '$ne': ''
                        },
                        'meta.category': strategy_category
                    }
                )
                queryset = queryset.filter(username__in=usernames)

        if belong_to:
            if bool(strtobool(recursively)):
                try:
                    group = ZTPGroup.objects.get(pk=belong_to)
                except ZTPGroup.DoesNotExist:
                    raise Http404
                '''
                SELECT * FROM ZTPUser
                WHERE belong_to_id IN(
                    SELECT id FROM ZTPGroup
                    WHERE tree_id=group.tree_id AND lft>=group.lft AND rght<=group.rght)
                '''
                descendants = group.get_descendants(include_self=True)
                queryset = queryset.filter(belong_to__pk__in=descendants)
            else:
                queryset = queryset.filter(belong_to__pk=belong_to)

        # if strategy_category:
        #     usernames = StrategyLog.objects.mongo_distinct(
        #         'username',
        #         {
        #             'username': {
        #                 '$exists': True,
        #                 '$ne': ''
        #             },
        #             'meta.category': strategy_category
        #         }
        #     )
        #     queryset = queryset.filter(username__in=usernames)

        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        # queryset = self.get_queryset()
        serializer = self.get_serializer(queryset, many=True)
        data = OrderedDict()
        for user in serializer.data:
            user['partner_count'] = 0
            user['app_count'] = 0
            user['visit_count'] = 0
            user['regions'] = []
            data[user['username']] = user

        # 交互用户数
        # 原始数据是有向图，将其转换为无向图的邻接表形式
        queryset = ShareLog.objects.mongo_aggregate([
            {
                '$group': {
                    '_id': '$username',
                    'send_to': {'$addToSet': '$send_to'}
                }
            }
        ])
        partner_graph = defaultdict(set)
        for agg in queryset:
            username = agg['_id']
            for send_to in agg['send_to']:
                partner_graph[username].add(send_to)
                partner_graph[send_to].add(username)
        for username, stat in data.items():
            stat['partner_count'] = len(partner_graph.get(username, []))

        # 访问应用数和次数
        user2visit = {visit.pop('username'): visit for visit in app_visit_serializer()}
        for username, stat in data.items():
            device_list = ZTPDevice.objects.filter(user__username=username).all()
            signed_terminal = len(device_list)
            stat.update({'signed_terminal': signed_terminal})
            safety_level = CreditGlobalAction.get_user_level(stat['safety_score'])
            stat.update({'safety_level': safety_level})
            if username in user2visit:
                stat.update(user2visit[username])
            else:
                stat.update({'app_count': 0, 'visit_count': 0})

        # 策略触发记录
        queryset2 = StrategyLog.objects.mongo_aggregate([
            {
                '$group': {
                    '_id': '$username',
                    'categories': {'$addToSet': {'$concat': ['$meta.category', '风险']}},
                    'names': {'$addToSet': '$meta.name'}
                }
            }
        ])
        queryset3 = StrategyLog.objects.mongo_aggregate([
            {
                '$group': {
                    '_id': '$username',
                    'uid': {'$addToSet': '$uid'}
                }
            }
        ])

        # 执行聚合查询
        # queryset4 = StrategyLog.objects.mongo_aggregate([
        #     {
        #         '$sort': {  # 排序阶段，按log_time降序排序
        #             'log_time': -1  # -1 表示降序
        #         }
        #     },
        #     {
        #         '$group': {  # 分组阶段，按username分组，并获取每个组的第一个client_ip
        #             '_id': '$username',
        #             'ip': {'$first': '$client_ip'}
        #         }
        #     }
        # ])
        user2strategies = {agg['_id']: (agg['categories'], agg['names']) for agg in queryset2}
        user3strategies = {agg['_id']: agg['uid'] for agg in queryset3}
        # username_to_ip_map = {item['_id']: item['ip'] for item in queryset4}
        # print(180, user2strategies)
        uid_channel_dict, uid_name_dict = get_uid_info()
        for username, stat in data.items():
            app_list = []
            win_list = []
            web_list = []
            linux_list = []
            stat['risks'], stat['strategies'] = user2strategies.get(username, ([], []))
            uids = user3strategies.get(username, [])
            for uid in uids:
                channel = uid_channel_dict.get(uid, -1)
                if channel == 0:
                    app_list.append(uid_name_dict[uid])
                    win_list.append(uid_name_dict[uid])
                    web_list.append(uid_name_dict[uid])
                    linux_list.append(uid_name_dict[uid])
                elif channel == 1:
                    app_list.append(uid_name_dict[uid])
                elif channel == 2:
                    win_list.append(uid_name_dict[uid])
                elif channel == 3:
                    web_list.append(uid_name_dict[uid])
                elif channel == 4:
                    linux_list.append(uid_name_dict[uid])
            stat["app_strategies"] = app_list
            stat["web_strategies"] = web_list
            stat["win_strategies"] = win_list
            stat["linux_strategies"] = linux_list
            stat["last_login_ip"] = stat['last_ip']
            stat["last_login_location"] = ''
            if stat['last_login_ip']:
                address = find_ip_location(stat['last_login_ip'])
                stat["last_login_location"] = address.get("city_name", "")
            # if username_to_ip_map.get(username):
            #     ip = username_to_ip_map.get(username, "")
            #     stat["last_login_ip"] = ip
            #     # 通过ip获取地理位置
            #     address = find_ip_location(ip)
            #     if address:
            #         stat["last_login_location"] = address.get("city_name", "")

            # 加上防止报错
            if not stat.get('regions'):
                stat['regions'] = []

        # # 地理位置记录，省份
        # queryset3 = CASLog.objects.mongo_aggregate([
        #     {
        #         '$match': {
        #             'ip_location.city_name': {
        #                 '$exists': True,
        #                 '$ne': ''
        #             }
        #         }
        #     },
        #     {
        #         '$group': {
        #             '_id': '$username',
        #             'regions': {'$addToSet': '$ip_location.region_name'}
        #         }
        #     }
        # ])
        # user2regions = {agg['_id']: agg['regions'] for agg in queryset3}
        # for username, stat in data.items():
        #     stat['regions'] = user2regions.get(username, [])

        data = list(data.values())
        # 按交互用户数、访问应用数、访问应用次数排序
        ordering = request.query_params.get('ordering')
        if ordering:
            if ordering.startswith('-'):
                reverse = True
                ordering = ordering[1:]
            else:
                reverse = False
            if ordering in self.ordering_fields:
                data.sort(key=lambda d: d[ordering], reverse=reverse)
        page = self.paginate_queryset(data)
        if page is not None:
            return self.get_paginated_response(page)
        return Response(data)


class DailySummaryView(mixins.RetrieveModelMixin,
                       generics.GenericAPIView):
    """每日用户总数/活跃数/异常数概览"""
    serializer_class = DailySummarySerializer

    def get_object(self):
        # yesterday = datetime.date.today() - datetime.timedelta(days=1)
        today = datetime.date.today()
        # 修正用户总数数据来源
        # obj = (DailySummary.objects.filter(date=yesterday).first() or
        #        DailySummary.objects.order_by('-date').first())
        # print("obj : ", obj)
        obj = None
        if not obj:
            # 用户总数包括禁用用户
            if WITH_WX:
                total = ZTPUser.objects.exclude(wx_user_id="").count()
            else:
                total = ZTPUser.objects.all().count()
            active_query = {
                    **date_eq('log_time', today),
                    'auth_result': {'$regex': r'_SUCCESS$'},
                    # 'auth_code': 7,
                    'auth_code': {'$in': [1, 7]},
                    'username': {
                        '$exists': True,
                        '$ne': ''
                    }
                }
            if DEFAULT_PLATFORM:
                active_query.update({'platform': DEFAULT_PLATFORM})
            active = len(CASLog.objects.mongo_distinct(
                'username', active_query
            ))

            abnormal_query = {
                    'username': {
                        '$exists': True,
                        '$ne': ''
                    },
                    **date_eq('log_time', today),
                    "uid": {"$ne": "STG/AUTH-3"}
                }
            if DEFAULT_PLATFORM:
                abnormal_query.update({'platform': DEFAULT_PLATFORM})
            abnormal_users = set(StrategyLog.objects.mongo_distinct(
                'username', abnormal_query
            ))
            obj = DailySummary(date=today, total=total, active=active,
                               inactive=total - active, abnormal=len(abnormal_users))
        return obj

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)


class UserDemandView(views.APIView):
    """用户需求分类统计"""

    def get(self, request, *args, **kwargs):
        queryset = UserDemand.objects.filter(demand__isnull=False) \
            .values('demand').annotate(name=F('demand'), count=Count('*')).values('name', 'count')
        data = list(queryset)
        return Response(data)


class AppTagView(views.APIView):
    """应用分类统计"""

    def get(self, request, *args, **kwargs):
        queryset = UserDemand.objects.annotate(name=F('app_tag')). \
            values('name').annotate(count=Count('name')).values('name', 'count')
        data = list(queryset)
        return Response(data)


class UserdataDocExport(views.APIView):
    permission_classes = (IsUUIDPermission,)

    def get(self, request, *args, **kwargs):
        username = kwargs['username']
        user = ZTPUser.objects.filter(username=username).first()
        if not user:
            res = Response({"msg": "用户不存在", "data": {}},
                           status=status.HTTP_404_NOT_FOUND)
            return res
        else:
            # 构建用户相关数据 (todo 临时文件删除机制)
            temp_file = os.path.join(BASE_DIR, "tools/doc/temp_file_%s.docx" % username)
            raw_data = handler_user_info(user)
            _success = exportWord(raw_data, temp_file)
            file_name = "用户报告_%s_%s.docx" % (username, str(datetime.date.today()))
            if _success:
                _file = open(temp_file, "rb")
                res = FileResponse(_file)
                res['Content-Type'] = 'application/octet-stream'
                res['Content-Disposition'] = ('attachment; filename=%s' % file_name).encode("utf-8")
                res['Access-Control-Expose-Headers'] = "*"
                res['Filename'] = quote(file_name)
            else:
                res = Response({"msg": "报告生成失败", "data": {}},
                               status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            return res


class AppVisitCountView(views.APIView):
    """访问应用数量和次数"""

    def get(self, request, *args, **kwargs):
        username = kwargs['username']
        platform = request.GET.get('platform')
        if not platform:
            platform = DEFAULT_PLATFORM
        else:
            if platform not in list(map(str, range(1, 5))):
                res = Response({"msg": "platform参数错误", "data": {}},
                               status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                return res
            platform = int(platform)
        data = app_visit_serializer(username, auth_code=7, platform=platform)
        return Response(data)


class AppVisitTrendView(views.APIView):
    """访问应用趋势图"""

    def get(self, request, *args, **kwargs):
        username = kwargs['username']
        platform = request.GET.get('platform')
        if not platform:
            platform = DEFAULT_PLATFORM
        else:
            if platform not in list(map(str, range(1, 5))):
                res = Response({"msg": "platform参数错误", "data": {}},
                               status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                return res
            platform = int(platform)
        date_from, date_to = date_filter(self.request.query_params)
        data = trend_graph_serializer(
            CASLog, 'resource',
            date_from, date_to,
            username=username,
            auth_code=7, platform=platform
        )
        return Response(data)


class GroupViewSet(viewsets.ReadOnlyModelViewSet):
    """组织列表"""
    queryset = ZTPGroup.objects.all()
    serializer_class = GroupSerializer

    def list(self, request, *args, **kwargs):
        # 取得所有根节点
        db_roots = self.get_queryset().filter(level=0).order_by('tree_id')
        results = []
        id_to_node = {}
        for db_root in db_roots:
            root_node = {
                'id': db_root.id,
                'name': db_root.name,
                'children': [],
            }
            results.append(root_node)
            id_to_node[db_root.id] = root_node
            # 取得每个根节点的子树
            sub_tree = db_root.get_descendants()
            # 遍历子树逐个获取并构建节点
            for db_node in sub_tree:
                parent = id_to_node[db_node.parent_id]
                node = {
                    'id': db_node.id,
                    'name': db_node.name,
                    'parent_id': db_node.parent_id,
                    'children': [],
                }
                parent['children'].append(node)
                id_to_node[db_node.id] = node

        return Response(data=results)


@api_view(["GET"])
def user_score(request):
    res = dict()
    res["status"] = 0
    res["msg"] = "success"
    res["data"] = dict()
    user_name = request.query_params.get("user_name")
    date_from, date_to = date_filter(request.query_params)
    # 获取到当前最新的分数与对应维度
    user = ZTPUser.objects.filter(username=user_name).all()
    if not user:
        res["status"] = 1
        res["msg"] = "请确认用户"
        return Response(res)
    user = user[0]
    uss = UserSafetyScore.objects.filter(user=user).order_by("-datetime")
    if uss:
        cur_uss = uss[0]
    else:
        return Response(res)
    cur_score = dict()
    cur_score["total"] = TOTAL_SAFETY_SCORE - cur_uss.total + cur_uss.safety_consciousness
    cur_score["user_profile"] = USER_PROFILE - cur_uss.user_profile
    cur_score["behaviour_preference"] = BEHAVIOUR_PREFERENCE - cur_uss.behaviour_preference
    cur_score["terminal_security"] = TERMINAL_SECURITY - cur_uss.terminal_security
    cur_score["user_relationship"] = USER_RELATION - cur_uss.user_relationship
    cur_score["safety_consciousness"] = cur_uss.safety_consciousness
    res["data"]["cur_score"] = cur_score
    if date_from and date_to:
        trend_uss = UserSafetyScore.objects.filter(user=user, datetime__lt=date_to,
                                                   datetime__gt=date_from).order_by("-datetime").all()
    else:
        trend_uss = UserSafetyScore.objects.filter(user=user).order_by("-datetime").all()
    res["data"]["trend"] = list()
    for tuss in trend_uss:
        temp_dict = dict()
        temp_dict["datetime"] = tuss.datetime
        temp_dict["total"] = TOTAL_SAFETY_SCORE - tuss.total + tuss.safety_consciousness
        res["data"]["trend"].append(temp_dict)
    return Response(res)


@api_view(["GET"])
def users_score(request):
    res = dict()
    res["status"] = 0
    res["msg"] = "success"
    res["data"] = list()
    # 取出最新的评估日期
    # newest_date = UserSafetyScore.objects.order_by("-datetime")[:1]
    # if newest_date:
    #     newest_date = newest_date[0].datetime
    # else:
    #     res["msg"] = "没有找到数据"
    #     res["status"] = 1
    #     return Response(res)
    # date_from = newest_date - datetime.timedelta(hours=6)
    # date_to = newest_date + datetime.timedelta(hours=6)
    now = timezone.now()
    # 计算前一天的时间
    yesterday = now - timezone.timedelta(days=1)
    # 取前后6小时作为当前的评估时间段，因为每次评估是隔离24个小时的，整体评估时间在30分钟内
    uss = UserCreditScore.objects.order_by("credit_score")[0:10]
    user_name_list = []
    for user in uss:
        user_name_list.append(user.user)
    first_analyze = False
    # 计算用户分数趋势
    last_user_score = dict()
    try:
        if WITH_WX:
            last_date = ZTPUser.objects.exclude(wx_user_id="")[0].score.order_by("-datetime")[
                1].datetime
        else:
            last_date = ZTPUser.objects.all()[0].score.order_by("-datetime")[1].datetime
        last_date_from = last_date - datetime.timedelta(hours=6)
        last_date_to = last_date + datetime.timedelta(hours=6)
        rating_uss = UserSafetyScore.objects.filter(datetime__lt=last_date_to, datetime__gt=last_date_from,
                                                    user__in=user_name_list).all()
        last_user_score = dict()
        for russ in rating_uss:
            username = russ.user
            total = UserCreditScoreDetails.objects.filter(user=username, datetime__date=yesterday.date()).first()
            if total:
                last_user_score[username] = total.credit_score
            else:
                last_user_score[username] = 400
    except IndexError:
        first_analyze = True
    for user in uss:
        temp_dict = dict()
        # username = russ.user
        # 获取当前分数
        # total_query = UserCreditScore.objects.filter(user=username).first()
        # if total_query:
        #     total = total_query.credit_score
        total = user.credit_score
        temp_dict["score"] = total
        username = user.user.username
        temp_dict["user_name"] = username
        name_set = ZTPUser.objects.filter(username=username).first()
        temp_dict["name"] = name_set.name
        if not first_analyze and last_user_score.get(user.user):
            last_score = last_user_score[user.user]
            cur_score = total
            temp_dict["rating"] = check_rating(cur_score, last_score)
        else:
            temp_dict["rating"] = 2
        res["data"].append(temp_dict)
    return Response(res)


@api_view(["POST"])
def user_logout(request):
    user_name = request.data.get("username")
    user = ZTPUser.objects.filter(username=user_name).first()
    if not user:
        return Response({"code": 1, "msg": "没有找到用户"})
    url = settings.CAS['SERVER'] + settings.CAS['USER_LOGOUT']
    try:
        requests.post(url, json={'username': user_name})
        # 推送到用户设备
        device_list = Device.objects.filter(last_user_id=user.id).all()
        for device in device_list:
            device.offline(username=user_name, body='管理员退出了您的账号登录',
                           level=2, title='用户退出登录')
        Device.objects.filter(last_user_id=user.id).update(online=False)
        return Response({"code": 0, "msg": "成功"})
    except:
        logger.error(traceback.format_exc())
        return Response({"code": 1, "msg": "登出异常"}, status=status.HTTP_400_BAD_REQUEST)


@api_view(["POST"])
def user_freeze(request):
    user_name = request.data.get("username")
    blocked = request.data.get("blocked")
    freeze_time = request.data.get("freeze_time", None)
    user = ZTPUser.objects.filter(username=user_name).first()
    if not user:
        return Response({"code": 1, "msg": "没有找到用户"})
    # 字符串转时间"2024-07-26 00:00:00"  +00
    if freeze_time:
        block_until = freeze_time+"+08:00"
    else:
        block_until = None
    if not user_name:
        return Response({"code": 1, "msg": "参数错误"})
    try:
        ZTPUser.objects.filter(username=user_name).update(blocked=blocked, block_until=block_until)
        ZTPUserCas.objects.filter(username=user_name).update(blocked=blocked, block_until=block_until)
        # 推送到用户设备
        device_list = Device.objects.filter(last_user_id=user.id).all()
        for device in device_list:
            device.offline(username=user_name, body='因安全策略管控，当前用户已被冻结',
                           level=2, title='冻结用户')
        Device.objects.filter(last_user_id=user.id).update(online=False)
        return Response({"code": 0, "msg": "成功"})
    except Exception as e:
        logger.error(traceback.format_exc())
        return Response({"code": 1, "msg": "内部服务器错误"})
    # user = .objects.filter(username=user_name).all()


@api_view(["GET"])
def user_share_detail(request):
    user_name = request.query_params.get("username")
    send_to = request.query_params.get("send_to")
    date_from, date_to = date_filter(request.query_params)
    page = request.query_params.get("page", 1)  # 默认第一页
    size = request.query_params.get("page_size", 10)  # 默认每页10条
    if (not user_name) and (not send_to):
        return Response({"code": 1, "msg": "参数错误"})
    try:
        total_query = [
            {'$match': {
                'send_to': send_to,
                'username': user_name
            }},
            {
                '$group': {
                    '_id': None,
                    'totalCount': {'$sum': 1}
                }
            }
        ]
        match = date_range('log_time', date_from, date_to)
        if match:
            total_query.insert(0, {'$match': match})
        total_query = ShareLog.objects.mongo_aggregate(total_query)
        for total_q in total_query:
            total_count = total_q.get("totalCount")
        page = int(page)
        size = int(size)
        skip = (page - 1) * size
        match = date_range('log_time', date_from, date_to)
        aggregations = [
            {
                '$match': {
                    'send_to': send_to,
                    "username": user_name
                }
            },
            {'$skip': skip},
            {'$limit': size}
        ]
        if match:
            aggregations.insert(0, {'$match': match})
        queryset = ShareLog.objects.mongo_aggregate(aggregations)
        data = [{"log_time": agg["log_time"], "username": agg["username"], "send_to": agg["send_to"], "url": agg["url"], "share_name": agg["share_name"]}
                for agg in queryset]
        return Response({"code": 0, "msg": "成功", "data": {
            "total": total_count,
            "page": page,
            "page_size": size,
            "results": data
        }})
    except Exception as e:
        logger.error(traceback.format_exc())
        return Response({"code": 1, "msg": "内部服务器错误"})


@api_view(["GET"])
def user_top10(request):
    data = []
    today = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
    # 在线top10
    # 计算昨天的日期
    yesterday = datetime.datetime.now() - datetime.timedelta(days=1)
    yesterday_start = datetime.datetime(yesterday.year, yesterday.month, yesterday.day)
    today_now = datetime.datetime.now()
    today_queryset = CASLog.objects.mongo_aggregate([
        {
            '$match': {
                '$and': [
                    {'username': {'$exists': True}},
                    # {'auth_result': {'$regex': r'_SUCCESS$'}},
                    {'auth_code': {'$in': [1, 7]}},
                    # ** date_range('log_time', yesterday_start, today_now)
                    {'log_time': {
                        '$gte': yesterday_start,
                        '$lte': today_now
                    }}
                ]
            }
        },
    ])
    today_username_list = list()
    for today_agg in today_queryset:
        today_username_list.append(today_agg['username'])
    today_username_list = list(set(today_username_list))
    # print("today_username_list : ", today_username_list)

    online_queryset = CASLog.objects.mongo_aggregate([
        {
            '$match': {
                '$and': [
                    {'username': {'$exists': True}},
                    {
                        '$or': [
                            {'auth_result': 'AUTHORIZE_SUCCESS'},
                            {'auth_result': 'AUTH_SUCCESS'}
                        ]
                    }
                ]
            }
        },
        {
            '$group': {
                '_id': '$username',
                'firstLogin': {'$min': '$log_time'},
                'lastLogin': {'$max': '$log_time'}
            }
        },
        {
            '$addFields': {
                'loginDurationDays': {
                    '$trunc': {
                        '$divide': [
                            {'$subtract': ['$lastLogin', '$firstLogin']},
                            1000 * 60 * 60 * 24
                        ]
                    }
                }
            }
        },
        {
            '$sort': {
                'loginDurationDays': -1  # -1 表示倒序
            }
        }
    ])
    n = 1
    online_dict = {"type": 0}
    online_top = list()
    for online_agg in online_queryset:
        # print(online_agg)
        online = ZTPUser.objects.filter(username=online_agg["_id"]).first()
        if online:
            name = online.name
        else:
            name = ""
        if online_agg["_id"] in today_username_list and online_agg["loginDurationDays"] >= 1:  # 活跃用户要求当天必须登录过
            online_top.append(
                {"seq_no": n, "name": name, "username": online_agg["_id"], "count_or_time": online_agg["loginDurationDays"]})
            n += 1
            if n > 10:
                break
    online_dict['user_info'] = online_top
    data.append(online_dict)
    # 离线top10
    offline_queryset = CASLog.objects.mongo_aggregate([
        {
            '$match': {
                '$and': [
                    {'username': {'$exists': True}},
                    {
                        '$or': [
                            {'auth_result': 'AUTHORIZE_SUCCESS'},
                            {'auth_result': 'AUTH_SUCCESS'}
                        ]
                    }
                ]
            }
        },
        {
            '$group': {
                '_id': '$username',  # 分组键为用户ID
                'lastLogin': {'$max': '$log_time'}  # 找到每个用户的最后一次登录时间
            }
        },
        {
            '$addFields': {
                'loginDurationDays': {
                    '$toInt': {
                        '$divide': [
                            {'$subtract': [
                                {'$toDate': {'$concat': [
                                    {'$toString': {'$year': today}}, '-',
                                    {'$toString': {'$month': today}}, '-',
                                    {'$toString': {'$dayOfMonth': today}}
                                ]}},
                                '$lastLogin'
                            ]},
                            1000 * 60 * 60 * 24  # 将毫秒转换为天
                        ]
                    }
                }
            }
        },
        {
            '$project': {
                '_id': 1,
                'loginDurationDays': 1,
            }
        },
        {
            '$sort': {
                'loginDurationDays': -1  # 按差值天数降序排序
            }
        }])
    m = 1
    offline_dict = {"type": 1}
    offline_top = list()
    for offline_agg in offline_queryset:
        # print(offline_agg)
        offline = ZTPUser.objects.filter(username=offline_agg["_id"]).first()
        if offline:
            name = offline.name
        else:
            name = ""
        if int(offline_agg["loginDurationDays"]) >= 1:  # 离线天数需要大于等于1
            offline_top.append(
                {"seq_no": m, "name": name, "username": offline_agg["_id"],
                 "count_or_time": int(offline_agg["loginDurationDays"])})
            m += 1
            if m > 10:
                break
    offline_dict['user_info'] = offline_top
    data.append(offline_dict)
    # 异常行为top10
    queryset = StrategyLog.objects.mongo_aggregate([
        {
            '$match': {
                'username': {
                    '$exists': True,
                }
            }
        },
        {
            '$group': {
                '_id': '$username',
                'total_num': {'$sum': 1}
            }
        },
        {
            '$sort': {
                'total_num': -1  # -1 表示倒序
            }
        }
    ])
    l = 1
    abnormal_dict = {"type": 2}
    abnormal_top = list()
    for agg in queryset:
        # print(680, agg)
        abnormal = ZTPUser.objects.filter(username=agg["_id"]).first()
        if abnormal:
            name = abnormal.name
        else:
            name = ""
        # print(l, agg)
        if agg["_id"]:
            abnormal_top.append(
                {"seq_no": l, "name": name, "username": agg["_id"], "count_or_time": agg["total_num"]})
            l += 1
        if l > 10:
            break
    abnormal_dict['user_info'] = abnormal_top
    data.append(abnormal_dict)
    return Response(data, status=status.HTTP_200_OK)


@api_view(["POST"])
def user_forbidden(request):
    user_name = request.data.get("username")
    enabled = request.data.get("enabled")
    user = ZTPUser.objects.filter(username=user_name).first()
    if not user:
        return Response({"code": 1, "msg": "没有找到用户"})
    try:
        ZTPUser.objects.filter(username=user_name).update(enabled=enabled)
        ZTPUserCas.objects.filter(username=user_name).update(enabled=enabled)
        # 推送到用户设备
        device_list = Device.objects.filter(last_user_id=user.id).all()
        for device in device_list:
            device.offline(username=user_name, body='登录失败，账号已被冻结或禁用，请联系管理员处理',
                           level=2, title='冻结用户')
        Device.objects.filter(last_user_id=user.id).update(online=False)
        return Response({"code": 0, "msg": "操作成功"})
    except Exception as e:
        logger.error(traceback.format_exc())
        return Response({"code": 1, "msg": "操作失败，内部服务器错误"})


@api_view(["GET"])
def user_credit_score(request):
    res = dict()
    res["status"] = 0
    res["msg"] = "success"
    res["data"] = dict()
    res["data"]["ticks"] = list()
    res["data"]["score_trend"] = list()
    res["data"]["score"] = 0
    res["data"]["risk_distribution"] = list()
    username = request.query_params.get("username")
    # 获取到当前最新的分数与对应维度
    user = ZTPUser.objects.filter(username=username).all()
    if not user:
        res["status"] = 1
        res["msg"] = "请确认用户"
        return Response(res)
    user = user[0]
    uss = UserCreditScoreDetails.objects.filter(user=user.username).order_by("-datetime")
    date_from = None
    if uss:
        cur_uss = uss[0]
        date_from = cur_uss.datetime
    else:
        return Response(res)

    ticks = CreditGlobalAction.objects.distinct().values_list('score_upper', flat=True)
    # res["data"]["score"] = random.randint(350, 420)  # 调试接口用
    res["data"]["ticks"] = sorted(list(ticks))

    # ------------------------------------------------------------------------------------------------------------------
    interval_days = datetime.timedelta(days=1)
    date_from = as_datetime(date_from - interval_days)
    # date_from = date_from.replace(tzinfo=None)
    # print("date_from : ", date_from)
    res["data"]["score_trend"] = list()
    # date_to = datetime.datetime.now()
    # print("date_to : ", date_to)
    # trend_uss = UserCreditScoreDetails.objects.filter(user=user, datetime__lt=date_to,
    #                                                datetime__gt=date_from).order_by("-datetime").all()
    trend_uss = UserCreditScoreDetails.objects.filter(user=user).order_by("-datetime").all()
    for tuss in trend_uss:
        date_list = [l_['date'] for l_ in res["data"]["score_trend"]]
        if to_date(tuss.datetime) not in date_list:
            temp_dict = dict()
            temp_dict["date"] = to_date(tuss.datetime)
            temp_dict["value"] = tuss.credit_score
            res["data"]["score_trend"].append(temp_dict)

    # 用户风险分布：[{ item: 身份认证, a: 实际分数, b: 满分 }]
    uss = UserCreditScore.objects.filter(user=user.username).first()
    terminal_score = uss.terminal_score
    resources_score = uss.resources_score
    env_score = uss.env_score
    behavior_score = uss.behavior_score
    devices_score = uss.devices_score
    res["data"]["score"] = uss.credit_score

    res["data"]["risk_distribution"] = [
        {"item": "终端威胁", "a": terminal_score, "b": 100},
        {"item": "访问资源", "a": resources_score, "b": 100},
        {"item": "环境基线", "a": env_score, "b": 100},
        {"item": "行为偏好", "a": behavior_score, "b": 100},
        {"item": "访问设备", "a": devices_score, "b": 100},
    ]

    return Response(res)


def check_rating(cur_score, last_score):
    if cur_score == last_score:
        return 2
    elif cur_score > last_score:
        return 1
    else:
        return 0


# @cache_page(60 * 10)
@api_view(["GET"])
def user_statistic(request):
    res = dict()
    res["status"] = 0
    res["msg"] = "success"
    res["data"] = dict()
    date_to = as_datetime(datetime.date.today())
    date_from = as_datetime(datetime.date.today() - datetime.timedelta(days=1))
    # 用户总数
    if WITH_WX:
        count = ZTPUser.objects.exclude(wx_user_id="").count()
    else:
        count = ZTPUser.objects.all().count()
    res["data"]["count"] = count
    # 一天内活跃用户数目计算
    active_querysets = CASLog.objects.mongo_distinct(
        'username',
        {
            'username': {
                '$exists': True,
                '$ne': ''
            },
            'log_time': {"$gte": date_from, "$lte": date_to},
            # "auth_code": 7
            'auth_code': {'$in': [1, 7]},
        }
    )
    active_num = len(active_querysets)
    res["data"]["active_num"] = active_num
    # 一天非活跃情况
    res["data"]["inactive_num"] = count - active_num
    # 一天行为异常用户数目计算
    abnormal_querysets = StrategyLog.objects.mongo_distinct(
        'username',
        {
            'username': {
                '$exists': True,
                '$ne': ''
            },
            'log_time': {"$gte": date_from, "$lte": date_to},
            "uid": {"$ne": "STG/AUTH-3"}
        }
    )
    abnormal_num = len(abnormal_querysets)
    res["data"]["abnormal_num"] = abnormal_num
    # 近一周详细数据统计
    res["data"]["week_status"] = list()
    for i in range(8):
        if i == 0:
            continue
        per_date_data = get_date_data(i, count)
        res["data"]["week_status"].append(per_date_data)
    return Response(res)


def get_date_data(i, count):
    date_to = as_datetime(datetime.date.today() - datetime.timedelta(days=i - 1))
    date_from = as_datetime(datetime.date.today() - datetime.timedelta(days=i))
    data = dict()
    data["date"] = to_date(date_from)
    data["active_count"] = len(CASLog.objects.mongo_distinct(
        'username',
        {
            'username': {
                '$exists': True,
                '$ne': ''
            },
            'log_time': {"$gte": date_from, "$lte": date_to},
            # "auth_code": 7
            'auth_code': {'$in': [1, 7]},
        }
    ))
    data["inactive_count"] = count - data["active_count"]
    data["abnormal_count"] = len(StrategyLog.objects.mongo_distinct(
        'username',
        {
            'username': {
                '$exists': True,
                '$ne': ''
            },
            'log_time': {"$gte": date_from, "$lte": date_to},
            "uid": {"$ne": "STG/AUTH-3"}
        }
    ))
    return data


@api_view(["GET"])
def users_score_distribution(request):
    res = dict()
    res["status"] = 0
    res["msg"] = "success"
    res["data"] = dict()
    if WITH_WX:
        us = UserCreditScore.objects.exclude(user__wx_user_id="")
    else:
        us = UserCreditScore.objects.all()
    unique_score_list = CreditGlobalAction.objects.order_by('score_upper').values_list('score_upper', flat=True).distinct()
    score_list = list(unique_score_list)

    highrisk_count = us.filter(credit_score__lt=score_list[0]).count()
    middlerisk_count = us.filter(credit_score__gte=score_list[0], credit_score__lt=score_list[1]).count()
    lowrisk_count = us.filter(credit_score__gte=score_list[1], credit_score__lt=score_list[2]).count()
    normal_count = us.filter(credit_score__gte=score_list[2]).count()
    res["data"]["normal"] = normal_count
    res["data"]["lower"] = lowrisk_count
    res["data"]["medium"] = middlerisk_count
    res["data"]["high"] = highrisk_count

    return Response(res)


@cache_page(60 * 10)
@api_view(['GET'])
def user_top(request):
    date_from, date_to = date_filter(request.query_params)
    queryset = CASLog.objects.mongo_aggregate([
        {
            '$match': {
                'auth_result': {"$auth_code": 7},
                'username': {
                    '$exists': True,
                    '$ne': ''
                },
                **date_range('log_time', date_from, date_to)
            }
        },
        {'$sortByCount': '$username'},
    ])
    users = [{'username': agg['_id'], 'count': agg['count']} for agg in queryset]
    top_active = users[:10]
    top_inactive = list(reversed(users[-10:]))
    username2name = dict(ZTPUser.objects.values_list('username', 'name'))
    for user in top_active + top_inactive:
        user['name'] = username2name.get(user['username'])
    data = {'active': top_active, 'inactive': top_inactive}
    return Response(data)


@cache_page(60 * 10)
@api_view(['GET'])
def app_installation_count(request):
    """应用装机情况统计"""
    queryset = AppsLog.objects.mongo_aggregate([
        {'$unwind': '$apps'},
        {
            '$match': {
                'apps.program_name': {
                    '$exists': True,
                    '$ne': ''
                },
                'device_info.device_uuid': {'$ne': ''}
            }
        },
        {
            '$group': {
                '_id': {
                    'program_name': '$apps.program_name',
                    'device_uuid': '$device_info.device_uuid'
                },
                'count': {'$sum': 1}
            }
        },
        {
            '$group': {
                '_id': '$_id.program_name',
                'count': {'$sum': 1}
            }
        },
        {'$sort': {'count': -1}},
        {'$limit': 10}
    ])

    data = [{'field': agg['_id'], 'count': agg['count']} for agg in queryset]
    return Response(data)


class UserRelationshipViewSet(viewsets.ReadOnlyModelViewSet):
    """
    用户文件/链接分享关系图
    有向图，A->B和B->A算作不同的边
    """
    queryset = ShareLog.objects.all()

    def get_object(self):
        lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
        return self.kwargs[lookup_url_kwarg]

    def list(self, request, *args, **kwargs):
        date_from, date_to = date_filter(request.query_params)
        data = relationship_serializer(**date_range('log_time', date_from, date_to))
        return Response(data)

    def retrieve(self, request, *args, **kwargs):
        date_from, date_to = date_filter(request.query_params)
        data = relationship_serializer(username=self.get_object(),
                                       **date_range('log_time', date_from, date_to))
        return Response(data)


class UserWarningViewSet(mixins.ListModelMixin,
                             mixins.RetrieveModelMixin,
                             viewsets.GenericViewSet):
    """
    用户预警
    """
    queryset = StrategyLog.objects.order_by('log_time')
    serializer_class = UserWarningSerializer
    pagination_class = PageSizePagination
    # filter_backends = (DjangoFilterBackend, SearchFilter)
    # filterset_fields = ('platform',)  # 字段没统一无法使用过滤
    # search_fields = ('username',)


    def list(self, request, *args, **kwargs):
        channel = self.request.query_params.get("channel")
        if channel and isinstance(channel, str):
            channel = int(channel)
        data = list()
        strategy_mapping = {1: 'Android', 2: 'Windows', 3: 'Web', 4: 'Linux'}
        strategy_dict = {group['uid']: group['name'] for group in Strategy.objects.values('uid', 'name')}
        strategy_result = self.get_mongo_queryset()
        for agg in strategy_result:
            username = agg['username']
            channels = []
            channels_str = []
            channels_info = []
            strategies_list = []
            platform_info = agg["platforms"]
            for platform_obj in platform_info:
                platform = strategy_mapping.get(platform_obj["platform"])
                log_entries = platform_obj["log_entries"]
                channels_str.append(platform)
                channels.append(platform_obj["platform"])
                channels_info.append({"channel_str": platform, "uid_info": [
                    {"activity": strategy_dict.get(entry["uid"]),
                     "log_time": (entry["log_time"]).strftime('%Y-%m-%d %H:%M:%S')} for entry in log_entries if
                    isinstance(entry, OrderedDict)]})
                if channel:
                    if channel == platform_obj["platform"]:
                        # 异常行为只展示过滤的行为
                        strategies_list.extend([strategy_dict.get(entry["uid"]) for entry in log_entries if isinstance(entry, OrderedDict)])
                else:
                    strategies_list.extend(
                        [strategy_dict.get(entry["uid"]) for entry in log_entries if isinstance(entry, OrderedDict)])
            user_queryset = ZTPUser.objects.filter(username=username).first()
            if not user_queryset:
                continue
            group_dict = {group['id']: group['name'] for group in ZTPGroup.objects.values('id', 'name')}
            department = group_dict.get(user_queryset.belong_to_id)
            # print(user_queryset.name, user_queryset.belong_to_id)
            safety_score = user_queryset.safety_score
            blocked = user_queryset.blocked
            enabled = user_queryset.enabled

            if enabled is False:
                status_str = "已禁用"
            elif enabled is True and blocked is False:
                status_str = "已启用"
            elif enabled is True and blocked is True:
                block_until = user_queryset.block_until
                if block_until:
                    if block_until.tzinfo is None or block_until.tzinfo != timezone.utc:
                        # 如果 tzinfo 不是 timezone.utc，或者没有设置 tzinfo，则将其设置为 UTC
                        block_until = block_until.replace(tzinfo=timezone.utc)
                    now = datetime.datetime.now(timezone.utc)
                    if now < block_until:
                        status_str = "已冻结"
                    else:
                        # 修改数据
                        ZTPUser.objects.filter(id=user_queryset.id).update(blocked=False, block_until=None)
                        ZTPUserCas.objects.filter(id=user_queryset.id).update(blocked=False, block_until=None)
                        status_str = "已启用"
                else:
                    # 修改数据
                    ZTPUser.objects.filter(id=user_queryset.id).update(blocked=False)
                    ZTPUserCas.objects.filter(id=user_queryset.id).update(blocked=False)
                    status_str = "已启用"
            channel_strs = ",".join(channels_str) if len(channels_str) > 0 else ""
            strategies = ",".join(set(strategies_list)) if len(strategies_list) > 0 else ""
            if channel:
                if channel in channels:
                    extracted_dict = {'id': user_queryset.id, 'username': agg['username'], 'name': user_queryset.name,
                                      'department': department, 'safe_credit_score': safety_score,
                                      'risk_level': get_risk_level(safety_score),
                                      'channel': channel_strs, 'strategies': strategies, 'channels_info': channels_info,
                                      'status': status_str, 'blocked': blocked, 'enabled': enabled}
                    data.append(extracted_dict)
            else:
                extracted_dict = {'id': user_queryset.id, 'username': agg['username'], 'name': user_queryset.name,
                                  'department': department, 'safe_credit_score': safety_score,
                                  'risk_level': get_risk_level(safety_score),
                                  'channel': channel_strs, 'strategies': strategies, 'channels_info': channels_info,
                                  'status': status_str, 'blocked': blocked, 'enabled': enabled}
                data.append(extracted_dict)

        page = self.paginate_queryset(data)
        if page is not None:
            return self.get_paginated_response(page)
        return Response(data, status=status.HTTP_200_OK)

    def get_mongo_queryset(self):
        aggregation = [
            {
                '$group': {
                    '_id': {
                        'username': '$username',
                        'platform': '$platform'
                    },
                    'log_entries': {
                        '$push': {
                            'uid': '$uid',
                            'log_time': '$log_time'
                        }
                    }
                }
            },
            {
                '$unwind': '$log_entries'  # 解构log_entries数组
            },
            {
                '$sort': {
                    '_id.username': 1,  # 也可以根据需要移除或调整
                    '_id.platform': 1,  # 也可以根据需要移除或调整
                    'log_entries.log_time': -1  # 按log_time倒序排序
                }
            },
            {
                '$group': {
                    '_id': {
                        'username': '$_id.username',
                        'platform': '$_id.platform'
                    },
                    'log_entries': {
                        '$push': '$log_entries'  # 重新聚合log_entries
                    }
                }
            },
            {
                '$group': {
                    '_id': '$_id.username',
                    'platforms': {
                        '$push': {
                            'platform': '$_id.platform',
                            'log_entries': '$log_entries'
                        }
                    }
                }
            },
            {
                '$project': {
                    'username': '$_id',
                    'platforms': 1,
                    '_id': 0
                }
            }
        ]
        date_from, date_to = date_filter(self.request.query_params)
        match = date_range('log_time', date_from, date_to)
        platform = self.request.query_params.get("channel")
        if platform:
            match["platform"] = int(platform)
        username = self.request.query_params.get("username", "") or self.request.query_params.get("search", "")
        print("username : ", username)
        if username:
            regex_pattern = re.compile(f'{re.escape(username)}', re.IGNORECASE)
            match["username"] = {"$regex": regex_pattern}
        if match:
            aggregation.insert(0, {'$match': match})
        # print(aggregation)
        queryset = StrategyLog.objects.mongo_aggregate(aggregation)
        return queryset


class UserActivityViewSet(mixins.ListModelMixin,
                          viewsets.GenericViewSet):
    """用户行为列表"""
    queryset = UserActivityLog.objects.order_by('-log_time')
    serializer_class = UserActivityLogSerializer
    pagination_class = PageSizePagination
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = ('username', 'abnormal', 'platform')

    def get_queryset(self):
        queryset = super().get_queryset()
        date_from, date_to = date_filter(self.request.query_params)
        date_from = as_datetime(date_from)
        date_to = as_datetime(date_to)
        if date_from:
            queryset = queryset.filter(log_time__gte=date_from)
        if date_to:
            queryset = queryset.filter(log_time__lte=date_to + datetime.timedelta(days=1))
        return queryset


class GeoTrackView(views.APIView):
    """用户地理轨迹信息"""

    def get(self, request, *args, **kwargs):
        date_from, date_to = date_filter(self.request.query_params)
        data = device_geotrack_serializer(username=kwargs['username'], show_devices=True,
                                          **date_range('log_time', date_from, date_to))
        return Response(data)


# todo 优化一下写法
class UserDeviceViewSet(viewsets.ReadOnlyModelViewSet):
    """用户详情 & 用户设备"""
    queryset = Device.objects.all()
    serializer_class = UserDeviceSerializer
    pagination_class = PageSizePagination
    filter_backends = (SearchFilter, DjangoFilterBackend)
    lookup_field = 'username'

    def get_queryset(self):
        user_name = self.request.query_params.get('user_name')
        platform = self.request.query_params.get('platform')
        if not platform:
            platform = DEFAULT_PLATFORM
        else:
            platform = int(platform)
        user_device = dict()
        user_name_info = User.objects.filter(username=user_name).first()  # 获取 username 对应的 user_id
        if user_name_info:
            user_id = user_name_info.id  # 获取用户id
            if platform:
                device_info = Device.objects.filter(user_id=user_id, platform=platform).all()  # 获取 device_id 对应的数据
            else:
                device_info = Device.objects.filter(user_id=user_id).all()  # 获取 device_id 对应的数据
            if device_info:
                user_device = dict()
                id_num = 0
                for device_info_ in device_info:
                    device_info_dict = dict()
                    id_num += 1
                    device_info_dict['id'] = device_info_.id
                    device_info_dict['device_type'] = device_info_.device_type
                    device_info_dict['device_type_str'] = device_info_.device_type_str
                    device_info_dict['device_uuid'] = device_info_.device_uuid
                    device_info_dict['model'] = device_info_.model
                    device_info_dict['os_version'] = device_info_.os_version
                    device_info_dict['strategy'] = device_info_.risk_list
                    user_device[id_num] = device_info_dict
        else:
            user_device = None

        return user_device

    def list(self, request, *args, **kwargs):
        data = self.get_queryset()
        if data is None:  # 当前用户不存
            return Response({"user_name": ['当前用户不存在']})
        elif type(data) == dict:  # 该用户存在
            data = list(data.values())
            page = self.paginate_queryset(data)
            if page is not None:
                return self.get_paginated_response(page)
            return Response({})
        else:
            return Response({})
